package com.blockserverclient;

import com.ByteBufferUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author 罗俊华
 * @date 2021/8/18 - 5:18 下午
 */
@Slf4j
public class Server {

    public static void main(String[] args) throws IOException {
//        使用 nio 来理解阻塞模式

//        1、创建服务器


//        2、绑定监听的端口
        ServerSocketChannel serverSocketChannel = ServerSocketChannel
                .open()
                .bind(new InetSocketAddress(2356));

//        配置为非阻塞模式，如果设置为 false，那么之后调用 serverSocketChannel.accept() 的时候，此方法将变为非阻塞方法
//        调用非阻塞的accept()方法，如果没有连接，那么此方法将返回 null
//        serverSocketChannel.configureBlocking(false);


//        ExecutorService executorService = Executors.newCachedThreadPool();

        ArrayList<SocketChannel> socketChannels = new ArrayList<>();

        while (true) {
            log.info("waiting for client connect...");
//        3、建立与客户端的连接，其中， socketChannel 用于与 client之间通信
            try (SocketChannel socketChannel = serverSocketChannel.accept()) {

//
                if (socketChannel != null) {
                    //                设置与客户端的连接通道为非阻塞（false），那么以后调用 socketChannel.read() 或者 socketChannel.write() 将成为
//                非阻塞方法
                    socketChannel.configureBlocking(false);
                    log.info("new client client connected...");
                    socketChannels.add(socketChannel);
                }
                for (SocketChannel channel : socketChannels) {

                    ByteBuffer receiveBuffer = ByteBuffer.allocate(128 * 1024 * 1024);
                    try {

                        log.info("waiting for client send data...");

    /*                    try (FileChannel fileOutputChannel = new FileOutputStream("/Users/luo/temp/temp-nacos-server.tar.gz").getChannel()) {
                            int read = 0;
//                        非阻塞的 read() 方法在没有读取到数据的时候，会返回0
                            while ((read = channel.read(receiveBuffer)) > 0) {
                                receiveBuffer.flip();
                                fileOutputChannel.write(receiveBuffer);
                                log.info("receive {} KB data from client", read / 1024);
                                receiveBuffer.compact();
                            }
                        }*/
                        int read = socketChannel.read(receiveBuffer);  // read 方法也是一个阻塞方法，等待有数据，然后进行读
                        log.info("received client {} byte data...",read);
                        ByteBufferUtil.debugAll(receiveBuffer);
                        receiveBuffer.flip();
                        System.out.println(StandardCharsets.UTF_8.decode(receiveBuffer));

                        ByteBuffer writeBuffer = StandardCharsets.UTF_8.encode("the response from server");
                        log.info("prepare to write response to client");
                        while (writeBuffer.hasRemaining()) {

                            channel.write(writeBuffer);
                        }
                        log.info("write success");
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }


            }

        }
    }
}
